cimport cython
import numpy as np
cimport numpy as np
import cv2
import math

cpdef unsigned char [:,:] preprocess(str image_path):
    """
    1.彩色加载
    2.转灰度
    :param image_path:
    :return:
    """
    # 读取图片
    image = cv2.imread(image_path)

    # 转成灰度
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    return image

cpdef float brenner(str image_path):
    """
    brenner梯度函数
    :param image:
    :return:
    """
    if isinstance(image_path, str):
        image = preprocess(image_path)
    else:
        image = image_path
    image = np.float32(image)
    x, y = image.shape
    score = 0
    for i in range(x - 2):
        sub = image[i+2,:]-image[i,:]
        score += cv2.sumElems(sub**2)[0]
    return score / (1.0 * x * y)

cpdef float tenengrad(str image_path):
    """
    :param image_path:
    :return:
    """
    if isinstance(image_path, str):
        image = preprocess(image_path)
    else:
        image = image_path
    image = np.float32(image)
    x, y = image.shape

    grad_x = cv2.Sobel(image, -1, 1, 0, ksize=3)
    grad_y = cv2.Sobel(image, -1, 0, 1, ksize=3)

    score = cv2.sumElems(cv2.sqrt((grad_x ** 2 + grad_y ** 2)))[0]
    return score / (1.0 * x * y)

def JPEQ(image_path):
    """

    :param image_path:
    :return:
    """

    def h_feature(x,M,N):

        d_h = np.zeros((M,N-1),np.float32)
        for j in range(N-1):
            d_h[:,j] = x[:,j+1] - x[:,j]

        DEL = math.floor(N/8) - 1

        d1_h = np.zeros((M,DEL),np.float32)

        for j in range(DEL):
            d1_h[:,j] = abs(d_h[:,8*j+7])

        B_h = cv2.mean(d1_h)[0]
        A_h = (8*cv2.mean(abs(d_h))[0]-B_h)/7

        sig_h = np.sign(d_h)

        left_sig = np.zeros((M,N-2),np.float32)
        right_sig = np.zeros((M,N-2),np.float32)

        for j in range(N-2):
            left_sig[:,j] = sig_h[:,j]
            right_sig[:,j] = sig_h[:,j+1]

        multi_sig = np.zeros((M,N-2),np.float32)

        for i in range(M):
            for j in range(N-2):
                template = left_sig[i,j] * right_sig[i,j]
                if template<0:
                    multi_sig[i,j] = 1
                else:
                    multi_sig[i,j] = 0

        Z_h = cv2.mean(multi_sig)[0]
        return A_h,B_h,Z_h

    def v_feature(x,M,N):

        d_v = np.zeros((M-1,N),np.float32)
        for i in range(M-1):
            d_v[i,:] = x[i+1,:]-x[i,:]

        DEV = math.floor(M/8)-1

        d1_v = np.zeros((DEV,N),np.float32)
        for i in range(DEV):
            d1_v[i,:] = abs(d_v[8*i+7,:])

        B_v = cv2.mean(d1_v)[0]
        A_v = (8*cv2.mean(abs(d_v))[0]-B_v)/7

        sig_v = np.sign(d_v)

        up_sig = np.zeros((M-2,N),np.float32)
        down_sig = np.zeros((M-2,N),np.float32)

        for i in range(M-2):
            up_sig[i,:] = sig_v[i,:]
            down_sig[i,:] = sig_v[i+1,:]

        multi_sig = np.zeros((M-2,N),np.float32)
        for i in range(M-2):
            for j in range(N):
                template = up_sig[i,j] * down_sig[i,j]
                if template<0:
                    multi_sig[i,j] = 1
                else:
                    multi_sig[i,j] = 0

        Z_v = cv2.mean(multi_sig)[0]

        return A_v,B_v,Z_v

    def combine_fearure(A_h,B_h,Z_h,A_v,B_v,Z_v):
        A = (A_h+A_v)/2
        B = (B_h+B_v) / 2
        Z = (Z_h+Z_v)/2

        return A,B,Z

    def compute_score(A,B,Z):
        alpha = -245.8909
        beta = 261.9373
        gamma1 = -239.8886
        gamma2 = 160.1664
        gamma3 = 64.2859

        score = alpha+beta*(pow(B,gamma1/10000)*pow(A,gamma2/10000)*pow(Z,gamma3/10000))

        return score

    if isinstance(image_path, str):
        image = preprocess(image_path)
    else:
        image = image_path
    image = np.float32(image)
    M,N = len(image),len(image[0])

    A_h, B_h, Z_h = h_feature(image,M,N)
    A_v, B_v, Z_v = v_feature(image, M, N)
    A,B,Z = combine_fearure(A_h,B_h,Z_h,A_v,B_v,Z_v)

    score = compute_score(A,B,Z)

    return score